# Copyright 2012-2016 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

"""Arguments parser for `maascli`."""


import argparse
import os
import sys

from maascli import api
from maascli.cli import register_cli_commands
from maascli.utils import parse_docstring


class ArgumentParser(argparse.ArgumentParser):
    """Specialisation of argparse's parser with better support for subparsers.

    Specifically, the one-shot `add_subparsers` call is disabled, replaced by
    a lazily evaluated `subparsers` property.
    """

    __subparsers = None

    def _print_error(self, message):
        """Print the specified message to stderr.

        This method is used to isolate write to stderr, so that those writes
        can be intercepted in a unit test.
        """
        sys.stderr.write(message)

    def __init__(self, *args, **kwargs):
        kwargs.setdefault(
            "formatter_class", argparse.RawDescriptionHelpFormatter
        )
        super().__init__(*args, **kwargs)

    def add_subparsers(self, title="drill down", metavar="COMMAND", **kwargs):
        assert (
            self.__subparsers is None
        ), "Only one group of subparsers allowed."
        self.__subparsers = super().add_subparsers(
            title=title, metavar=metavar, **kwargs
        )
        return self.__subparsers

    @property
    def subparsers(self):
        if self.__subparsers is not None:
            return self.__subparsers
        else:
            return self.add_subparsers()

    def error(self, message):
        """Make the default error messages more helpful

        Override default ArgumentParser error method to print the help menu
        generated by ArgumentParser instead of just printing out a list of
        valid arguments.
        """
        self.print_help(sys.stderr)
        self._print_error("\n" + message + "\n")
        sys.exit(2)


def get_deepest_subparser(parser, argv):
    """Recursive function to find the best matching subparser."""
    if not argv:
        return parser
    maybe_parser, *rest = argv
    sub_parser = parser.subparsers._name_parser_map.get(maybe_parser)
    if sub_parser is None:
        return parser
    else:
        return get_deepest_subparser(sub_parser, rest)


def prepare_parser(argv):
    """Create and populate an arguments parser for the maascli command."""
    help_title, help_body = parse_docstring(api)
    parser = ArgumentParser(
        description=help_body,
        prog=os.path.basename(argv[0]),
        epilog="https://maas.io/",
    )
    register_cli_commands(parser)
    api.register_api_commands(parser)
    parser.add_argument(
        "--debug", action="store_true", default=False, help=argparse.SUPPRESS
    )
    return parser
